import pandas as pd
import string
import networkx as nx
import numpy as np
import plotly.graph_objs as go
from plotly.subplots import make_subplots
from scipy.spatial import distance_matrix
import scipy.spatial as spt
from scipy.spatial.distance import pdist, squareform
Из R мы имеем 2 дата фрейма. Первый — с ребрами, второй с частотой встречаемости каждой вершины (ее степенью). Нужно обработать каждый из них — привести теги к общему виду, после этого убрать, встречающиеся реже 50 раз, потом преобразовать список ребер.
MC_nodes = pd.read_csv('NA_Moscowcase_nodes_R-data.csv') # Загружаем то, что есть(вершины)
MC_nodes.sort_values(by = 'Freq', ascending = False).head()
| Unnamed: 0 | Var1 | Freq | |
|---|---|---|---|
| 2022 | 2023 | #московскоедело | 1827 |
| 3286 | 3287 | #сядьзатекст | 604 |
| 2983 | 2984 | #свободуполитзаключенным | 457 |
| 2391 | 2392 | #отпускай | 235 |
| 1996 | 1997 | #москва | 224 |
Далее, пытаемся преобразовать теги.
разделим каждое значение по знаку "#" т.к. иногда попадаются теги типа #freedomofassembly#moscowcase#sergeifomin#egorzhukov#humanrights#freedom (будем учитывать каждую составляющую этого тега, встречаемость оставим для каждого аналогичную большому тегу) или ##россиябудетсвободной (чтобы он тег #россиябудетсвободной считались как один). Это частные примеры, таких больше.
уберем все знаки препинания
MC_tags = []
MC_count = []
for i in range(len(list(MC_nodes['Var1']))):
L = list(MC_nodes['Var1'])[i].split('#')
for not_empty in L:
if len(not_empty) != 0:
MC_tags.append(not_empty)
MC_count.append(list(MC_nodes['Freq'])[i])
MC_tags = list(map(lambda x: '#' + x.translate(str.maketrans('', '', string.punctuation)).lower(), MC_tags))
#MC_tags
Соберем это в датафрейм.
df = pd.DataFrame(list(zip(MC_tags, MC_count)), columns = ['Tag', 'Freq'])
df.head()
| Tag | Freq | |
|---|---|---|
| 0 | #u4e2du56fd | 1 |
| 1 | #feminism | 1 |
| 2 | #like | 1 |
| 3 | #россиябудетсвободной | 1 |
| 4 | #свободуполитзаключенным | 1 |
Сделаем словарь с частотой встречаемости каждого тега. Отрежем те, которые встречаются менее 50 раз. Сохранеим все, что получилось, в датафрейм.
dict_MC = {}
for i in list(set(list(df['Tag']))):
dict_MC[i] = int(df[df['Tag'] == i]['Freq'].sum())
#dict_MC
MC_nodes = pd.DataFrame(list(zip(dict_MC.keys(), dict_MC.values())), columns = ['Tag', 'Freq'])
MC_nodes = MC_nodes[MC_nodes['Freq'] > 50]
MC_nodes.sort_values(by = 'Freq', ascending = False).head()
MC_nodes['Color'] = [1]*MC_nodes.shape[0] # еще добавим вершинам цвет, чтобы потом на графике отличать группы тегов
MC_nodes.to_csv('NA_Moscowcase_nodes_Python-data.csv')
Все, работа с вершинами закончена. По сути она была нужна только для того, чтобы отсеить реше всех встречающиемся вершины. Теперь отсюда нам нужна только первая колонка с названиями тегов + цвета.
MC_edges = pd.read_csv('NA_Moscowcase_edges_R-data.csv').drop(['Unnamed: 0'],axis=1) # Загружаем то, что есть(ребра)
MC_edges.head()
| V1 | V2 | V3 | V4 | V5 | V6 | V7 | V8 | V9 | V10 | ... | V22 | V23 | V24 | V25 | V26 | V27 | V28 | V29 | V30 | V31 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | #politics | #history | #political | #жуков | #московскоедело | #история | #поэзия | #poet | #poetry | #inspirationalquotes | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
| 1 | #московскоедело | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
| 2 | #московскоедело | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
| 3 | #Мордор | #МосковскоеДело | #МусораХужеГовна | #ВсеПутинскиеСудьиБляди | NaN | NaN | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
| 4 | #МосковскоеДело | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
5 rows × 31 columns
Пару слов о том, что из себя представляет эта таблица. Каждая строка = один пост из инстаграма, в котором встречается хэштег #Московскоедело. Точнее не сам пост, а именно теги из него. Собственно ребра будут построены комбинацией друг с другом тегов из каждого поста = получим кортежи.
Сначала преобразуме таблицу в более рабочее состоянее. Сделаем список, элементами которого будут строки из таблицы = списки (т.е. будет список кортежей) с уже преобразованными по вышеупомянутой "технологии" спопосбом.
Tags = list(MC_nodes['Tag'])
MC_edgelist = []
for i in range(MC_edges.shape[0]):
L = list(MC_edges.loc[i, :]) # просто строка
L = [x for x in L if str(x) != 'nan'] # убрали из нее nan
L_final = []
for l in range(len(L)):
sub_L = L[l].split('#') # разделили каждый эл-т по #
for not_empty in sub_L:
if len(not_empty) != 0:
L_final.append(not_empty) # оставили в списке только слова без # (зачем это делалалось объясняли выше)
# преобразуем слова в полученном списке, делаем множеством потому что ранее заявили, что теги по типу #свободуегоружукову и #СвободуЕгоруЖукову равнозначны
L_final = list(set(list(map(lambda x: '#' + x.translate(str.maketrans('', '', string.punctuation)).lower(), L_final))))
L_final.sort()
# остается оставить только те теги, которые ранее было заявлены как самые встречающиеся (MC_nodes['Tag'])
L_final = [l_f for l_f in L_final if l_f in Tags]
L_tags = []
# теперь нужно сделать кортежи из L_final
time = 0
for l_1 in range(time, len(L_final)):
for l_2 in range(time+1, len(L_final)):
L_tags.append((L_final[l_1], L_final[l_2]))
time +=1
if len(L_tags) != 0:
MC_edgelist.extend(L_tags)
len(set(MC_edgelist)) #получили наши 839 ребра
839
MC_edges = list(set(MC_edgelist))
MC_edges_1 = []
MC_edges_2 = []
for i in range(len(MC_edges)):
MC_edges_1.append(MC_edges[i][0])
MC_edges_2.append(MC_edges[i][1])
MC_edges = pd.DataFrame(list(zip(MC_edges_1, MC_edges_2)), columns = ['Var1', 'Var2'])
MC_edges.head()
| Var1 | Var2 | |
|---|---|---|
| 0 | #росгвардия | #свободукотову |
| 1 | #свободукотову | #фбк |
| 2 | #арестанты212 | #стоп212 |
| 3 | #суд | #ямыпавелустинов |
| 4 | #свободуполитзаключенным | #сядьзатекст |
MC_edges.shape # все наши 839 ребра на месте
(839, 2)
MC_edges.to_csv('NA_Moscowcase_edges_Python-data.csv')
Аналогичные шаги для тегов #Мосгордума и #Допускай. В итоге у нас будет 3 обработанных датафрейма.
def get_edges(tag, color):
filename_nodes = 'NA_' + str(tag) + '_nodes_R-data.csv'
Nodes = pd.read_csv(filename_nodes) # Загружаем то, что есть(вершины)
Tags = []
Count = []
for i in range(len(list(Nodes['Var1']))):
L = list(Nodes['Var1'])[i].split('#')
for not_empty in L:
if len(not_empty) != 0:
Tags.append(not_empty)
Count.append(list(Nodes['Freq'])[i])
Tags = list(map(lambda x: '#' + x.translate(str.maketrans('', '', string.punctuation)).lower(), Tags))
df = pd.DataFrame(list(zip(Tags, Count)), columns = ['Tag', 'Freq'])
dict_Nodes = {}
for i in list(set(list(df['Tag']))):
dict_Nodes[i] = int(df[df['Tag'] == i]['Freq'].sum())
Nodes = pd.DataFrame(list(zip(dict_Nodes.keys(), dict_Nodes.values())), columns = ['Tag', 'Freq'])
Nodes = Nodes[Nodes['Freq'] > 50]
Nodes['Color'] = [color]*Nodes.shape[0] # еще добавим вершинам цвет, чтобы потом на графике отличать группы тегов
filename = 'NA_' + str(tag) + '_nodes_Python-data.csv'
Nodes.to_csv(filename)
filename_edges = 'NA_' + str(tag) + '_edges_R-data.csv'
Edges = pd.read_csv(filename_edges).drop(['Unnamed: 0'],axis=1) # Загружаем то, что есть(ребра)
Tags = list(Nodes['Tag'])
Edgelist = []
for i in range(Edges.shape[0]):
L = list(Edges.loc[i, :]) # просто строка
L = [x for x in L if str(x) != 'nan'] # убрали из нее nan
L_final = []
for l in range(len(L)):
sub_L = L[l].split('#') # разделили каждый эл-т по #
for not_empty in sub_L:
if len(not_empty) != 0:
L_final.append(not_empty) # оставили в списке только слова без # (зачем это делалалось объясняли выше)
# преобразуем слова в полученном списке, делаем множеством потому что ранее заявили, что теги по типу #свободуегоружукову и #СвободуЕгоруЖукову равнозначны
L_final = list(set(list(map(lambda x: '#' + x.translate(str.maketrans('', '', string.punctuation)).lower(), L_final))))
L_final.sort()
# остается оставить только те теги, которые ранее было заявлены как самые встречающиеся (MC_nodes['Tag'])
L_final = [l_f for l_f in L_final if l_f in Tags]
L_tags = []
# теперь нужно сделать кортежи из L_final
time = 0
for l_1 in range(time, len(L_final)):
for l_2 in range(time+1, len(L_final)):
L_tags.append((L_final[l_1], L_final[l_2]))
time +=1
if len(L_tags) != 0:
Edgelist.extend(L_tags)
Edges = list(set(Edgelist))
Edges_1 = []
Edges_2 = []
for i in range(len(Edges)):
Edges_1.append(Edges[i][0])
Edges_2.append(Edges[i][1])
Edges = pd.DataFrame(list(zip(Edges_1, Edges_2)), columns = ['Var1', 'Var2'])
filename = 'NA_' + str(tag) + '_edges_Python-data.csv'
Edges.to_csv(filename)
get_edges('Moscowcase', '#ed4830') # можно самому задать цвет группы :)
get_edges('Mosgorduma', '#00ff7f')
get_edges('Dopuskai', '#afdafc')
На всякий случай все данные сохранила отдельно в архив. Осталось создать единый датафрейм.
#### Вершины ####
Moscowcase_n = pd.read_csv('NA_Moscowcase_nodes_Python-data.csv')
Mosgorduma_n = pd.read_csv('NA_Mosgorduma_nodes_Python-data.csv')
Dopuskai_n = pd.read_csv('NA_Dopuskai_nodes_Python-data.csv')
Nodes = []
Colors_n = []
Nodes.extend(Moscowcase_n['Tag'])
Colors_n.extend(Moscowcase_n['Color'])
Nodes.extend(Mosgorduma_n['Tag'])
Colors_n.extend(Mosgorduma_n['Color'])
Nodes.extend(Dopuskai_n['Tag'])
Colors_n.extend(Dopuskai_n['Color'])
#### Ребра ####
edgelist = []
Moscowcase_e = pd.read_csv('NA_Moscowcase_edges_Python-data.csv')
Mosgorduma_e = pd.read_csv('NA_Mosgorduma_edges_Python-data.csv')
Dopuskai_e = pd.read_csv('NA_Dopuskai_edges_Python-data.csv')
for i in range(Moscowcase_e.shape[0]):
edgelist.append((Moscowcase_e['Var1'][i], Moscowcase_e['Var2'][i]))
for i in range(Mosgorduma_e.shape[0]):
edgelist.append((Mosgorduma_e['Var1'][i], Mosgorduma_e['Var2'][i]))
for i in range(Dopuskai_e.shape[0]):
edgelist.append((Dopuskai_e['Var1'][i], Dopuskai_e['Var2'][i]))
Для #московскоедело #мосгордума и #допускай зададим отдельные цвета.
nodes = dict(zip(Nodes, Colors_n))
nodes['#московскоедело'] = '#cc0605'
nodes['#мосгордума'] = '#007d34'
nodes['#допускай'] = '#007cad'
G = nx.Graph()
G.add_edges_from(edgelist, weight = 1)
Коллективно было принято решение рисовать 3D граф, ибо это 1) прикольно, 2) красиво, 3) можно вращать(!) Учебник - https://plot.ly/python/v3/3d-network-graph/
labels = []
degree = []
color = []
for i in list(G.nodes):
labels.append(i)
degree.append(G.degree[i])
color.append(nodes[i])
layt=nx.spring_layout(G, dim=3, k = 1)
Xn=[layt[k][0] for k in list(G.nodes)]# x-coordinates of nodes
Yn=[layt[k][1] for k in list(G.nodes)]# y-coordinates
Zn=[layt[k][2] for k in list(G.nodes)]# z-coordinates
Xe=[]
Ye=[]
Ze=[]
for e in G.edges:
Xe+=[layt[e[0]][0],layt[e[1]][0], None]# x-coordinates of edge ends
Ye+=[layt[e[0]][1],layt[e[1]][1], None]
Ze+=[layt[e[0]][2],layt[e[1]][2], None]
trace1=go.Scatter3d(x=Xe, y=Ye, z=Ze,
mode='lines',
line=dict(color='black', width=0.2),
hoverinfo='none')
trace2=go.Scatter3d(x=Xn, y=Yn, z=Zn,
mode='markers',
marker=dict(symbol='circle',
size=degree,
color=color,
opacity = 0.9,
showscale =False,
line=dict(color='black', width=0.3)),
text=labels,
hovertemplate =
'<b>%{text}</b>' +
'<br><i>Degree</i>: %{marker.size}' +
'<extra></extra>')
axis=dict(showbackground=False,
showline=False,
zeroline=False,
showgrid=False,
showticklabels=False,
title=''
)
layout = go.Layout(
title="Moscow summer 2019",
width=1000,
height=1000,
showlegend=False,
scene=dict(
xaxis=dict(axis),
yaxis=dict(axis),
zaxis=dict(axis)),
hovermode='closest')
data=[trace1, trace2]
fig=go.Figure(data=data, layout=layout)
fig.show()
G.number_of_edges() # количество ребер
3036
G.number_of_nodes() # количество вершин
134
# степени вершин
degrees = G.degree
print('\nDegrees')
for i in degrees:
print(f"\tNode {i[0]}, Degree {i[1]}")
Degrees Node #росгвардия, Degree 86 Node #свободукотову, Degree 37 Node #фбк, Degree 79 Node #арестанты212, Degree 38 Node #стоп212, Degree 22 Node #суд, Degree 36 Node #ямыпавелустинов, Degree 33 Node #свободуполитзаключенным, Degree 72 Node #сядьзатекст, Degree 42 Node #егоржуков, Degree 42 Node #путин, Degree 95 Node #свободуегоружукову, Degree 65 Node #oxxxymiron, Degree 35 Node #протест, Degree 90 Node #moscow, Degree 68 Node #константинкотов, Degree 39 Node #жуковнеэкстремист, Degree 20 Node #ямывсястрана, Degree 39 Node #москва, Degree 125 Node #московскоедело, Degree 67 Node #выборы, Degree 106 Node #допускай, Degree 99 Node #свобода, Degree 68 Node #политика, Degree 103 Node #russia, Degree 70 Node #мирныйпротестнетерроризм, Degree 25 Node #одиночныйпикет, Degree 36 Node #россиябудетсвободной, Degree 68 Node #павелустинов, Degree 39 Node #оксимирон, Degree 33 Node #россия, Degree 109 Node #митинги, Degree 66 Node #свободуполитзаключённым, Degree 35 Node #полиция, Degree 72 Node #дело212, Degree 44 Node #митинг, Degree 98 Node #навальный, Degree 92 Node #политзаключенные, Degree 41 Node #свободупавлуустинову, Degree 38 Node #отпускай, Degree 87 Node #стыдностоятьвстороне, Degree 26 Node #метропикет, Degree 28 Node #мосгордума, Degree 100 Node #свободувсем, Degree 36 Node #хватитмолчать, Degree 23 Node #пикет, Degree 35 Node #8сентября, Degree 32 Node #марьино, Degree 28 Node #некрасовка, Degree 31 Node #госдума, Degree 75 Node #егоровао, Degree 27 Node #правительствомосквы, Degree 36 Node #гд, Degree 31 Node #рязанский, Degree 34 Node #собянин, Degree 36 Node #безопаснаястолица, Degree 9 Node #выборы2019, Degree 97 Node #лдпртв, Degree 28 Node #южнопортовый, Degree 27 Node #mos, Degree 27 Node #такаявласть, Degree 27 Node #мойрайон, Degree 11 Node #оппозиция, Degree 62 Node #кпрф, Degree 69 Node #печатники, Degree 27 Node #дума, Degree 26 Node #новости, Degree 74 Node #умноеголосование, Degree 82 Node #зюзино, Degree 16 Node #лдпр, Degree 83 Node #зелао, Degree 29 Node #ювао, Degree 35 Node #капотня, Degree 28 Node #текстильщики, Degree 28 Node #выхино, Degree 31 Node #голосование, Degree 27 Node #жулебино, Degree 31 Node #лефортово, Degree 28 Node #люблино, Degree 31 Node #мгд2019, Degree 32 Node #власть, Degree 72 Node #мосгордума2019, Degree 30 Node #единаяроссия, Degree 84 Node #жириновский, Degree 39 Node #кузьминки, Degree 29 Node #votemoscow, Degree 3 Node #мгд, Degree 42 Node #депутат, Degree 52 Node #голосмосква, Degree 3 Node #властьпротивнарода, Degree 21 Node #путинвор, Degree 66 Node #мыесть, Degree 37 Node #честныевыборы, Degree 49 Node #путинуходи, Degree 41 Node #митингмосква, Degree 43 Node #правительство, Degree 50 Node #ворыувласти, Degree 24 Node #питер, Degree 49 Node #любовьсоболь, Degree 51 Node #народ, Degree 41 Node #медведев, Degree 54 Node #сми, Degree 47 Node #жуликииворы, Degree 39 Node #революция, Degree 37 Node #путинскаяроссия, Degree 37 Node #repost, Degree 72 Node #законнуженсейчас, Degree 6 Node #украина, Degree 42 Node #астрахань, Degree 27 Node #коррупция, Degree 55 Node #омон, Degree 53 Node #путлер, Degree 14 Node #шиес, Degree 43 Node #властьнароду, Degree 39 Node #стоппутин, Degree 15 Node #соболь, Degree 49 Node #иркутск, Degree 50 Node #протесты, Degree 49 Node #надоел, Degree 33 Node #долойвласть, Degree 21 Node #кремль, Degree 50 Node #факты, Degree 29 Node #санктпетербург, Degree 46 Node #яшин, Degree 43 Node #россиябезпутина, Degree 32 Node #беспредел, Degree 41 Node #дорогнет, Degree 15 Node #едимроссию, Degree 35 Node #другоемнение, Degree 29 Node #зачестныевыборы, Degree 45 Node #долойпутина, Degree 22 Node #корупция, Degree 34 Node #путинлжец, Degree 35 Node #помогите, Degree 6
# вес ребер
print(f'Weight \n{nx.to_numpy_matrix(G, dtype=np.int)}')
Weight [[0 1 1 ... 1 1 0] [1 0 1 ... 0 0 0] [1 1 0 ... 1 0 0] ... [1 0 1 ... 0 0 0] [1 0 0 ... 0 0 0] [0 0 0 ... 0 0 0]]
fig = go.Figure(go.Histogram(
x=np.array(list(dict(G.degree()).values())),
xbins=dict(size=10),
marker=dict(color = '#00a550',
line = dict(color = 'black', width = 1))))
fig.update_layout(margin=dict(t=30, b=10, r=10, l=10), title_text = "Распределение степеней вершин",
xaxis={'title':'Степени вершин'},
yaxis={'title':'Количество'})
fig.show()
print(f'Диаметр {nx.diameter(G)}')
print(f'Транзитивность {nx.transitivity(G)}')
print(f'Плотность {nx.density(G)}')
Диаметр 3 Транзитивность 0.6300871719633958 Плотность 0.34070250252496914
# Degree centrality
deg = nx.centrality.degree_centrality(G)
# Closeness centrality
clos = nx.centrality.closeness_centrality(G)
# Betweenness
bet = nx.centrality.betweenness_centrality(G)
# Eigenvector
eigen = nx.centrality.eigenvector_centrality(G)
# Эти графики тоже можно вращать, приближать и удалять, имя вершины и знчение мер появляются при наведении на кругляш
trace1=go.Scatter3d(x=Xe, y=Ye, z=Ze,
mode='lines',
line=dict(color='black', width=0.2),
hoverinfo='none')
# For Degree centrality
trace2_1=go.Scatter3d(x=Xn, y=Yn, z=Zn,
mode='markers',
marker=dict(symbol='circle',
size = list(map(lambda x: x*50 , list(deg.values()))), # содержательно домножение ни на что не повлияет, просто кругляши будут больше
color=list(map(lambda x: round(x, 3) , list(deg.values()))),
opacity = 0.9,
showscale =True,
colorscale = 'Viridis',
colorbar=dict(title='Measures'),
line=dict(color='black', width=0.5)),
text=labels,
hovertemplate =
'<b>%{text}</b>' +
'<br><i>Degree centrality</i>: %{marker.color}' +
'<extra></extra>')
# For Closeness centrality
trace2_2=go.Scatter3d(x=Xn, y=Yn, z=Zn,
mode='markers',
marker=dict(symbol='circle',
size = list(map(lambda x: x*30 , list(clos.values()))),
color=list(map(lambda x: round(x, 3) , list(clos.values()))),
opacity = 0.9,
showscale = False,
colorscale = 'Viridis',
line=dict(color='black', width=0.5)),
text=labels,
hovertemplate =
'<b>%{text}</b>' +
'<br><i>Closeness centrality</i>: %{marker.color}' +
'<extra></extra>')
# For Betweenness
trace2_3=go.Scatter3d(x=Xn, y=Yn, z=Zn,
mode='markers',
marker=dict(symbol='circle',
size = list(map(lambda x: x*1000 , list(bet.values()))),
color=list(map(lambda x: round(x, 3) , list(bet.values()))),
opacity = 0.9,
showscale = False,
colorscale = 'Viridis',
line=dict(color='black', width=0.5)),
text=labels,
hovertemplate =
'<b>%{text}</b>' +
'<br><i>Betweenness</i>: %{marker.color}' +
'<extra></extra>')
# For Eigenvector
trace2_4=go.Scatter3d(x=Xn, y=Yn, z=Zn,
mode='markers',
marker=dict(symbol='circle',
size = list(map(lambda x: x*150 , list(eigen.values()))),
color=list(map(lambda x: round(x, 3) , list(eigen.values()))),
opacity = 0.9,
showscale = False,
colorscale = 'Viridis',
line=dict(color='black', width=0.5)),
text=labels,
hovertemplate =
'<b>%{text}</b>' +
'<br><i>Eigenvector</i>: %{marker.color}' +
'<extra></extra>')
fig = make_subplots(rows=2, cols=2,
specs=[[{'is_3d': True}, {'is_3d': True}], [{'is_3d': True}, {'is_3d': True}]],
subplot_titles=("Degree centrality","Closeness centrality", "Betweenness", 'Eigenvector'),
vertical_spacing=0.1)
fig.add_trace(trace1, row=1, col=1)
fig.add_trace(trace2_1, row=1, col=1)
fig.add_trace(trace1, row=1, col=2)
fig.add_trace(trace2_2, row=1, col=2)
fig.add_trace(trace1, row=2, col=1)
fig.add_trace(trace2_3, row=2, col=1)
fig.add_trace(trace1, row=2, col=2)
fig.add_trace(trace2_4, row=2, col=2)
fig.update_layout(scene = dict(xaxis = dict(showticklabels=False, title = ''),
yaxis = dict(showticklabels=False, title = ''),
zaxis = dict(showticklabels=False, title = '')),
scene2 = dict(xaxis = dict(showticklabels=False, title = ''),
yaxis = dict(showticklabels=False, title = ''),
zaxis = dict(showticklabels=False, title = '')),
scene3 = dict(xaxis = dict(showticklabels=False, title = ''),
yaxis = dict(showticklabels=False, title = ''),
zaxis = dict(showticklabels=False, title = '')),
scene4 = dict(xaxis = dict(showticklabels=False, title = ''),
yaxis = dict(showticklabels=False, title = ''),
zaxis = dict(showticklabels=False, title = '')))
fig.update_layout(
title_text='3D Moscow summer 2019',
height=1000,
width=900, showlegend=False)
fig.show()
# Выведем ТОП-10 по каждой мере
def top_k_nodes(clos, k=10):
return pd.Series(clos).sort_values(ascending=False).reset_index().rename({'index': 'node', 0: 'centrality'}, axis=1).head(k)
# Degree centrality
top_k_nodes(deg)
| node | centrality | |
|---|---|---|
| 0 | #москва | 0.939850 |
| 1 | #россия | 0.819549 |
| 2 | #выборы | 0.796992 |
| 3 | #политика | 0.774436 |
| 4 | #мосгордума | 0.751880 |
| 5 | #допускай | 0.744361 |
| 6 | #митинг | 0.736842 |
| 7 | #выборы2019 | 0.729323 |
| 8 | #путин | 0.714286 |
| 9 | #навальный | 0.691729 |
# Closeness centrality
top_k_nodes(clos)
| node | centrality | |
|---|---|---|
| 0 | #москва | 0.943262 |
| 1 | #россия | 0.847134 |
| 2 | #выборы | 0.831250 |
| 3 | #политика | 0.815951 |
| 4 | #мосгордума | 0.801205 |
| 5 | #допускай | 0.796407 |
| 6 | #митинг | 0.791667 |
| 7 | #выборы2019 | 0.786982 |
| 8 | #путин | 0.777778 |
| 9 | #навальный | 0.764368 |
# Betweenness
top_k_nodes(bet)
| node | centrality | |
|---|---|---|
| 0 | #москва | 0.090014 |
| 1 | #мосгордума | 0.056859 |
| 2 | #выборы2019 | 0.048269 |
| 3 | #россия | 0.039316 |
| 4 | #выборы | 0.038317 |
| 5 | #допускай | 0.028943 |
| 6 | #политика | 0.028658 |
| 7 | #лдпр | 0.026408 |
| 8 | #умноеголосование | 0.021058 |
| 9 | #митинг | 0.020876 |
# Eigenvector
top_k_nodes(eigen)
| node | centrality | |
|---|---|---|
| 0 | #москва | 0.171118 |
| 1 | #россия | 0.162756 |
| 2 | #выборы | 0.159047 |
| 3 | #политика | 0.158001 |
| 4 | #митинг | 0.155449 |
| 5 | #допускай | 0.153759 |
| 6 | #путин | 0.152568 |
| 7 | #навальный | 0.150453 |
| 8 | #протест | 0.148882 |
| 9 | #росгвардия | 0.145150 |
# Page-Rank
pr = nx.pagerank(G)
# Hubs и Authorities
h, a = nx.hits(G)
fig = make_subplots(rows=2, cols=2, subplot_titles=("Page-Rank vs Degree centrality",
"Page-Rank vs Closeness centrality",
"Page-Rank vs Betweenness",
"Page-Rank vs Eigenvector"))
fig.add_trace(
go.Scatter(x=list(deg.values()), y=list(pr.values()), mode="markers",
hovertemplate =
'<i>Degree centrality</i>: %{x}' +
'<br><i>Page-Rank</i>: %{y}' +
'<extra></extra>'),
row=1, col=1
)
fig.add_trace(
go.Scatter(x=list(clos.values()), y=list(pr.values()), mode="markers",
hovertemplate =
'<i>Closeness centrality</i>: %{x}' +
'<br><i>Page-Rank</i>: %{y}' +
'<extra></extra>'),
row=1, col=2
)
fig.add_trace(
go.Scatter(x=list(bet.values()), y=list(pr.values()), mode="markers",
hovertemplate =
'<i>Betweenness</i>: %{x}' +
'<br><i>Page-Rank</i>: %{y}' +
'<extra></extra>'),
row=2, col=1
)
fig.add_trace(
go.Scatter(x=list(eigen.values()), y=list(pr.values()), mode="markers",
hovertemplate =
'<i>Eigenvector</i>: %{x}' +
'<br><i>Page-Rank</i>: %{y}' +
'<extra></extra>'),
row=2, col=2
)
fig.update_layout(height=700, width=900, title_text="Page-Rank", showlegend=False)
fig.update_xaxes(title_text="Degree centrality", row=1, col=1)
fig.update_xaxes(title_text="Closeness centrality", row=1, col=2)
fig.update_xaxes(title_text="Betweenness", row=2, col=1)
fig.update_xaxes(title_text="Eigenvector", row=2, col=2)
for i in range(1,3):
for j in range(1,3):
fig.update_yaxes(title_text="Page-Rank", row=i, col=j)
fig.show()
fig = make_subplots(rows=2, cols=2, subplot_titles=("Hubs vs Degree centrality",
"Hubs vs Closeness centrality",
"Hubs vs Betweenness",
"Hubs vs Eigenvector"))
fig.add_trace(
go.Scatter(x=list(deg.values()), y=list(h.values()), mode="markers",
hovertemplate =
'<i>Degree centrality</i>: %{x}' +
'<br><i>Hubs</i>: %{y}' +
'<extra></extra>'),
row=1, col=1
)
fig.add_trace(
go.Scatter(x=list(clos.values()), y=list(h.values()), mode="markers",
hovertemplate =
'<i>Closeness centrality</i>: %{x}' +
'<br><i>Hubs</i>: %{y}' +
'<extra></extra>'),
row=1, col=2
)
fig.add_trace(
go.Scatter(x=list(bet.values()), y=list(h.values()), mode="markers",
hovertemplate =
'<i>Betweenness</i>: %{x}' +
'<br><i>Hubs</i>: %{y}' +
'<extra></extra>'),
row=2, col=1
)
fig.add_trace(
go.Scatter(x=list(eigen.values()), y=list(h.values()), mode="markers",
hovertemplate =
'<i>Eigenvector</i>: %{x}' +
'<br><i>Hubs</i>: %{y}' +
'<extra></extra>'),
row=2, col=2
)
fig.update_layout(height=700, width=900, title_text="Hubs", showlegend=False)
fig.update_xaxes(title_text="Degree centrality", row=1, col=1)
fig.update_xaxes(title_text="Closeness centrality", row=1, col=2)
fig.update_xaxes(title_text="Betweenness", row=2, col=1)
fig.update_xaxes(title_text="Eigenvector", row=2, col=2)
for i in range(1,3):
for j in range(1,3):
fig.update_yaxes(title_text="Hubs", row=i, col=j)
fig.show()
fig = make_subplots(rows=2, cols=2, subplot_titles=("Authorities vs Degree centrality",
"Authorities vs Closeness centrality",
"Authorities vs Betweenness",
"Authorities vs Eigenvector"))
fig.add_trace(
go.Scatter(x=list(deg.values()), y=list(a.values()), mode="markers",
hovertemplate =
'<i>Degree centrality</i>: %{x}' +
'<br><i>Authorities</i>: %{y}' +
'<extra></extra>'),
row=1, col=1
)
fig.add_trace(
go.Scatter(x=list(clos.values()), y=list(a.values()), mode="markers",
hovertemplate =
'<i>Closeness centrality</i>: %{x}' +
'<br><i>Authorities</i>: %{y}' +
'<extra></extra>'),
row=1, col=2
)
fig.add_trace(
go.Scatter(x=list(bet.values()), y=list(a.values()), mode="markers",
hovertemplate =
'<i>Betweenness</i>: %{x}' +
'<br><i>Authorities</i>: %{y}' +
'<extra></extra>'),
row=2, col=1
)
fig.add_trace(
go.Scatter(x=list(eigen.values()), y=list(a.values()), mode="markers",
hovertemplate =
'<i>Eigenvector</i>: %{x}' +
'<br><i>Authorities</i>: %{y}' +
'<extra></extra>'),
row=2, col=2
)
fig.update_layout(height=700, width=900, title_text="Authorities", showlegend=False)
fig.update_xaxes(title_text="Degree centrality", row=1, col=1)
fig.update_xaxes(title_text="Closeness centrality", row=1, col=2)
fig.update_xaxes(title_text="Betweenness", row=2, col=1)
fig.update_xaxes(title_text="Eigenvector", row=2, col=2)
for i in range(1,3):
for j in range(1,3):
fig.update_yaxes(title_text="Authorities", row=i, col=j)
fig.show()
trace1=go.Scatter3d(x=Xe, y=Ye, z=Ze,
mode='lines',
line=dict(color='black', width=0.2),
hoverinfo='none')
# For Page-Rank
trace2_1=go.Scatter3d(x=Xn, y=Yn, z=Zn,
mode='markers',
marker=dict(symbol='circle',
size = list(map(lambda x: x*2000, list(pr.values()))),
color=list(map(lambda x: round(x, 3) , list(pr.values()))),
opacity = 0.9,
showscale =True,
colorscale = 'Viridis',
colorbar=dict(title='Measures'),
line=dict(color='black', width=0.5)),
text=labels,
hovertemplate =
'<b>%{text}</b>' +
'<br><i>Page-Rank</i>: %{marker.color}' +
'<extra></extra>')
# For Hubs
trace2_2=go.Scatter3d(x=Xn, y=Yn, z=Zn,
mode='markers',
marker=dict(symbol='circle',
size = list(map(lambda x: x*2000 , list(h.values()))),
color=list(map(lambda x: round(x, 3) , list(h.values()))),
opacity = 0.9,
showscale = False,
colorscale = 'Viridis',
colorbar=dict(title='Hubs'),
line=dict(color='black', width=0.5)),
text=labels,
hovertemplate =
'<b>%{text}</b>' +
'<br><i>Hubs</i>: %{marker.color}' +
'<extra></extra>')
# For Authorities
trace2_3=go.Scatter3d(x=Xn, y=Yn, z=Zn,
mode='markers',
marker=dict(symbol='circle',
size = list(map(lambda x: x*2000 , list(a.values()))),
color=list(map(lambda x: round(x, 3) , list(a.values()))),
opacity = 0.9,
showscale = False,
colorscale = 'Viridis',
colorbar=dict(title='Authorities'),
line=dict(color='black', width=0.5)),
text=labels,
hovertemplate =
'<b>%{text}</b>' +
'<br><i>Authorities</i>: %{marker.color}' +
'<extra></extra>')
fig = make_subplots(rows=1, cols=3,
specs=[[{'is_3d': True}, {'is_3d': True}, {'is_3d': True}]],
subplot_titles=("Page-Rank","Hubs", "Authorities"),
vertical_spacing=0.1)
fig.add_trace(trace1, row=1, col=1)
fig.add_trace(trace2_1, row=1, col=1)
fig.add_trace(trace1, row=1, col=2)
fig.add_trace(trace2_2, row=1, col=2)
fig.add_trace(trace1, row=1, col=3)
fig.add_trace(trace2_3, row=1, col=3)
fig.update_layout(scene = dict(xaxis = dict(showticklabels=False, title = ''),
yaxis = dict(showticklabels=False, title = ''),
zaxis = dict(showticklabels=False, title = '')),
scene2 = dict(xaxis = dict(showticklabels=False, title = ''),
yaxis = dict(showticklabels=False, title = ''),
zaxis = dict(showticklabels=False, title = '')),
scene3 = dict(xaxis = dict(showticklabels=False, title = ''),
yaxis = dict(showticklabels=False, title = ''),
zaxis = dict(showticklabels=False, title = '')))
fig.update_layout(
title_text='Moscow summer 2019',
height=500,
width=1350, showlegend=False)
fig.show()
# Page-Rank
top_k_nodes(pr)
| node | centrality | |
|---|---|---|
| 0 | #москва | 0.019187 |
| 1 | #россия | 0.016625 |
| 2 | #мосгордума | 0.016322 |
| 3 | #выборы | 0.016121 |
| 4 | #выборы2019 | 0.015895 |
| 5 | #политика | 0.015550 |
| 6 | #допускай | 0.015220 |
| 7 | #митинг | 0.014697 |
| 8 | #путин | 0.014286 |
| 9 | #навальный | 0.013788 |
# Hubs
top_k_nodes(h)
| node | centrality | |
|---|---|---|
| 0 | #москва | 0.016739 |
| 1 | #россия | 0.015921 |
| 2 | #выборы | 0.015558 |
| 3 | #политика | 0.015456 |
| 4 | #митинг | 0.015207 |
| 5 | #допускай | 0.015041 |
| 6 | #путин | 0.014925 |
| 7 | #навальный | 0.014718 |
| 8 | #протест | 0.014564 |
| 9 | #росгвардия | 0.014199 |
# Authorities
top_k_nodes(a)
| node | centrality | |
|---|---|---|
| 0 | #москва | 0.016739 |
| 1 | #россия | 0.015921 |
| 2 | #выборы | 0.015558 |
| 3 | #политика | 0.015456 |
| 4 | #митинг | 0.015207 |
| 5 | #допускай | 0.015041 |
| 6 | #путин | 0.014925 |
| 7 | #навальный | 0.014718 |
| 8 | #протест | 0.014564 |
| 9 | #росгвардия | 0.014199 |
ac = nx.degree_assortativity_coefficient(G)
print(f"Ассортативное смешивание с точки зрения степеней вершин: {ac}")
Ассортативное смешивание с точки зрения степеней вершин: -0.1405090355816136
A = nx.to_numpy_array(G, dtype=int)
D = np.corrcoef(A)
dVec1 = spt.distance.squareform(spt.distance.pdist(A, metric = 'euclidean'))
dVec2 = spt.distance.squareform(spt.distance.pdist(A, metric = 'cosine'))
fig = make_subplots(rows=2, cols=2, vertical_spacing=0.1, subplot_titles=("Adjacency Matrix", "Correlation coeff.",
"Euclidean Dist.", "Cosine Dist."))
fig.add_trace(go.Heatmap(z=A, colorscale= 'Viridis', showscale=True), row=1, col=1)
fig.add_trace(go.Heatmap(z=D, colorscale= 'Viridis', showscale=False), row=1, col=2)
fig.add_trace(go.Heatmap(z=dVec1, colorscale= 'Viridis', showscale=False), row=2, col=1)
fig.add_trace(go.Heatmap(z=dVec2, colorscale= 'Viridis', showscale=False), row=2, col=2)
fig.update_layout(height=900, width=900)
fig.show()
Теперь с помощью алгоритма Cuthill-McKey изменим в порядок вершин в матрицах
def cm_transform(G):
A = nx.to_numpy_array(G)
cm = list(nx.utils.reverse_cuthill_mckee_ordering(G))
cm_num = []
for i in cm:
cm_num.append(list(G.nodes).index(i))
return A[cm_num][:, cm_num]
newA = cm_transform(G)
newD = np.corrcoef(newA)
newdVec1 = spt.distance.squareform(spt.distance.pdist(newA, metric = 'euclidean'))
newdVec2 = spt.distance.squareform(spt.distance.pdist(newA, metric = 'cosine'))
fig = make_subplots(rows=2, cols=2, vertical_spacing=0.1, subplot_titles=("Adjacency Matrix", "Correlation coeff.",
"Euclidean Dist.", "Cosine Dist."))
fig.add_trace(go.Heatmap(z=newA, colorscale= 'Viridis', showscale=True), row=1, col=1)
fig.add_trace(go.Heatmap(z=newD, colorscale= 'Viridis', showscale=False), row=1, col=2)
fig.add_trace(go.Heatmap(z=newdVec1, colorscale= 'Viridis', showscale=False), row=2, col=1)
fig.add_trace(go.Heatmap(z=newdVec2, colorscale= 'Viridis', showscale=False), row=2, col=2)
fig.update_layout(height=900, width=900)
fig.show()
clique = []
for i in nx.clique.find_cliques(G):
clique.append(i)
#clique
clique_tup = []
for i in clique:
clique_tup.append((len(i), i))
clique_tup.sort()
clique_tup[-3:] # три наибольшие клики
[(30, ['#москва', '#выборы', '#россия', '#политика', '#навальный', '#путин', '#допускай', '#митинг', '#росгвардия', '#протест', '#фбк', '#отпускай', '#полиция', '#митинги', '#коррупция', '#выборы2019', '#новости', '#путинвор', '#единаяроссия', '#repost', '#власть', '#оппозиция', '#госдума', '#медведев', '#лдпр', '#сми', '#питер', '#кремль', '#омон', '#правительство']), (30, ['#москва', '#выборы', '#россия', '#политика', '#навальный', '#путин', '#допускай', '#митинг', '#росгвардия', '#протест', '#фбк', '#отпускай', '#полиция', '#митинги', '#мосгордума', '#выборы2019', '#единаяроссия', '#repost', '#новости', '#кпрф', '#власть', '#оппозиция', '#омон', '#медведев', '#лдпр', '#питер', '#сми', '#кремль', '#госдума', '#правительство']), (30, ['#москва', '#выборы', '#россия', '#политика', '#навальный', '#путин', '#допускай', '#митинг', '#росгвардия', '#протест', '#фбк', '#отпускай', '#полиция', '#митинги', '#мосгордума', '#выборы2019', '#единаяроссия', '#repost', '#новости', '#путинвор', '#власть', '#медведев', '#лдпр', '#омон', '#оппозиция', '#питер', '#сми', '#кремль', '#госдума', '#правительство'])]
clique1 = clique_tup[-1]
clique2 = clique_tup[-2]
clique3 = clique_tup[-3]
def clique_color(G, clique):
clique_dict = {}
for i in list(G.nodes):
if i in clique[1]:
clique_dict[i] = 2
else:
clique_dict[i] = 1
return clique_dict
clique1_dict = clique_color(G, clique1)
clique2_dict = clique_color(G, clique2)
clique3_dict = clique_color(G, clique3)
trace1=go.Scatter3d(x=Xe, y=Ye, z=Ze,
mode='lines',
line=dict(color='black', width=0.2),
hoverinfo='none')
# For clique1
trace2_1=go.Scatter3d(x=Xn, y=Yn, z=Zn,
mode='markers',
marker=dict(symbol='circle',
size = 8,
color=list(clique1_dict.values()),
opacity = 0.9,
line=dict(color='black', width=0.5)),
text=labels,
hovertemplate =
'<b>%{text}</b>' +
'<extra></extra>')
# For clique2
trace2_2=go.Scatter3d(x=Xn, y=Yn, z=Zn,
mode='markers',
marker=dict(symbol='circle',
size = 8,
color=list(clique2_dict.values()),
opacity = 0.9,
line=dict(color='black', width=0.5)),
text=labels,
hovertemplate =
'<b>%{text}</b>' +
'<extra></extra>')
# For clique3
trace2_3=go.Scatter3d(x=Xn, y=Yn, z=Zn,
mode='markers',
marker=dict(symbol='circle',
size = 8,
color=list(clique3_dict.values()),
opacity = 0.9,
line=dict(color='black', width=0.5)),
text=labels,
hovertemplate =
'<b>%{text}</b>' +
'<extra></extra>')
fig = make_subplots(rows=1, cols=3,
specs=[[{'is_3d': True}, {'is_3d': True}, {'is_3d': True}]],
subplot_titles=("Clique1","Clique2","Clique3"),
vertical_spacing=0.1)
fig.add_trace(trace1, row=1, col=1)
fig.add_trace(trace2_1, row=1, col=1)
fig.add_trace(trace1, row=1, col=2)
fig.add_trace(trace2_2, row=1, col=2)
fig.add_trace(trace1, row=1, col=3)
fig.add_trace(trace2_2, row=1, col=3)
fig.update_layout(scene = dict(xaxis = dict(showticklabels=False, title = ''),
yaxis = dict(showticklabels=False, title = ''),
zaxis = dict(showticklabels=False, title = '')),
scene2 = dict(xaxis = dict(showticklabels=False, title = ''),
yaxis = dict(showticklabels=False, title = ''),
zaxis = dict(showticklabels=False, title = '')),
scene3 = dict(xaxis = dict(showticklabels=False, title = ''),
yaxis = dict(showticklabels=False, title = ''),
zaxis = dict(showticklabels=False, title = '')))
fig.update_layout(
title_text='Moscow summer 2019',
height=500,
width=1350, showlegend=False)
fig.show()